package de.bomberman.appstate;

import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.FlyByCamera;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.BloomFilter;
import com.jme3.post.filters.FogFilter;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial.CullHint;
import de.bomberman.debug.Axes;
import de.bomberman.debug.Config;
import de.bomberman.world.DefaultLevel;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;
import java.util.logging.Logger;

/**
 *
 * @author Mats
 */
public class GameState extends AbstractAppState implements ScreenController {

    protected Node rootNode = new Node("Game Root Node");
    protected Node guiNode = new Node("Game Gui Node");
    private BitmapText fpsText;
    private BitmapText levelInfoText;
    protected FlyByCamera flyCam;
    private MainApp app = null;
    private AppActionListener actionListener;
    // nifty
    private Nifty nifty;
    private NiftyJmeDisplay niftyDisplay;
    // level
    int levelSize = 5;
    // Logger
    private static final Logger logger = Logger.getLogger(GameState.class.getName());

    public GameState(MainApp app) {
        this.app = app;
        init();
    }

    private void init() {
        // initLevel
        DefaultLevel defaultLevel = new DefaultLevel(levelSize, app, rootNode);
        rootNode.attachChild(defaultLevel.getLevelNode());

        // initBloom
        FilterPostProcessor fpp = new FilterPostProcessor(app.getAssetManager());
        BloomFilter bloom = new BloomFilter();
        fpp.addFilter(bloom);
        app.getViewPort().addProcessor(fpp);

        // initLight
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(-3, -4, -3));
        rootNode.addLight(sun);

        // initCamera
        app.getCamera().setLocation(new Vector3f(levelSize, 20, levelSize * 3));
        app.getCamera().lookAt(new Vector3f(levelSize, 0, levelSize), Vector3f.UNIT_Y);

        // initAxes
        if (Config.DEBUG_AXES) {
            Axes axes = new Axes(app, new Vector3f(0, 2, 0));
            rootNode.attachChild(axes.getAxes());
        }

        // init actionListener
        actionListener = new AppActionListener();


    }

    private class AppActionListener implements ActionListener {

        @Override
        public void onAction(String name, boolean isPressed, float tpf) {
            if (isPressed) {
                return;
            }
            switch (name) {
                case "Exit":
                    app.stop();
                    break;
                case "Menu":
                    app.loadMenu();
            }
        }
    }

    public void loadText() {
        BitmapFont guiFont = app.getAssetManager().loadFont("Interface/Fonts/Default.fnt");
        BitmapFont guiFontConsole = app.getAssetManager().loadFont("Interface/Fonts/Console.fnt");
        fpsText = new BitmapText(guiFont, false);
        fpsText.setSize(guiFont.getCharSet().getRenderedSize());
        fpsText.setLocalTranslation(0, fpsText.getLineHeight(), 0);
        fpsText.setText("Frames per second");
        guiNode.attachChild(fpsText);


        BitmapText menuText = new BitmapText(guiFont, false);
        menuText.setSize(guiFont.getCharSet().getRenderedSize());
        menuText.setLocalTranslation(0, (app.getContext().getSettings().getHeight() / 2f) - (menuText.getLineHeight() / 2), 0);
        menuText.setText("Press [M]\nto go back to the menu");
        menuText.setColor(ColorRGBA.White);
        guiNode.attachChild(menuText);

        levelInfoText = new BitmapText(guiFontConsole, false);
        levelInfoText.setSize(14);
        levelInfoText.setLocalTranslation(0, (app.getContext().getSettings().getHeight()) - (levelInfoText.getLineHeight() / 2), 0);
        levelInfoText.setColor(ColorRGBA.White);
        guiNode.attachChild(levelInfoText);
    }

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        super.initialize(stateManager, app);
        // enable depth test and back faces culling for perfomance
        app.getRenderer().applyRenderState(RenderState.DEFAULT);

        guiNode.setQueueBucket(RenderQueue.Bucket.Gui);
        guiNode.setCullHint(CullHint.Never);
        loadText();

        if (app.getInputManager() != null) {
            if (Config.ENABLE_FLYCAM) {
                flyCam = new FlyByCamera(app.getCamera());
                flyCam.setMoveSpeed(25f);
                flyCam.registerWithInput(app.getInputManager());
                flyCam.setEnabled(Config.ENABLE_FLYCAM);
            }

            app.getInputManager().addMapping("Exit", new KeyTrigger(KeyInput.KEY_ESCAPE));
            app.getInputManager().addMapping("Menu", new KeyTrigger(KeyInput.KEY_M));
        }

        // nifty
        if (niftyDisplay == null) {
            niftyDisplay = new NiftyJmeDisplay(app.getAssetManager(),
                    app.getInputManager(),
                    app.getAudioRenderer(),
                    app.getGuiViewPort());
        }
        nifty = niftyDisplay.getNifty();
        nifty.fromXml("Interface/Nifty/hud.xml", "hud", this);
        app.getGuiViewPort().addProcessor(niftyDisplay);
    }

    @Override
    public void update(float tpf) {
        super.update(tpf);

        int fps = (int) app.getTimer().getFrameRate();
        fpsText.setText("Frames per second: " + fps);

        levelInfoText.setText(DefaultLevel.getFieldString());
        // simple update and root node
        rootNode.updateLogicalState(tpf);
        guiNode.updateLogicalState(tpf);
        rootNode.updateGeometricState();
        guiNode.updateGeometricState();

        // Element fpsElement = nifty.getCurrentScreen().findElementByName("fps");
        // fpsElement.getRenderer(TextRenderer.class).setText("FPS: " + String.valueOf(fps));
    }

    @Override
    public void stateAttached(AppStateManager stateManager) {
        super.stateAttached(stateManager);
        app.getInputManager().addListener(actionListener, "Exit", "Menu");
        if (flyCam != null) {
            flyCam.setEnabled(Config.ENABLE_FLYCAM);
        }
        app.getViewPort().attachScene(rootNode);
        app.getGUIViewPort().attachScene(guiNode);
    }

    @Override
    public void stateDetached(AppStateManager stateManager) {
        super.stateDetached(stateManager);
        app.getInputManager().removeListener(actionListener);
        if (flyCam != null) {
            flyCam.setEnabled(false);
        }
        app.getViewPort().detachScene(rootNode);
        app.getGUIViewPort().detachScene(guiNode);
        app.getGuiViewPort().removeProcessor(niftyDisplay);
    }

    @Override
    public void bind(Nifty nifty, Screen screen) {
    }

    @Override
    public void onStartScreen() {
    }

    @Override
    public void onEndScreen() {
    }
}
